Датасет содержит информацию о вакцинации против Covid-2019 в различных странах мира
Цель проекта: проанализировать данные используя визуализацию и статистические критерии, построить предсказание временного ряда
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
import plotly.express as px
import geopandas
import statsmodels.api as sm
from statsmodels.tsa.stattools import adfuller
from statsmodels.tsa.statespace.sarimax import SARIMAX
import scipy
from statsmodels.tsa.arima.model import ARIMA
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_percentage_error
from itertools import product
from tqdm import tqdm
import warnings
warnings.filterwarnings("ignore", category=RuntimeWarning)
warnings.filterwarnings('ignore')
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
df = pd.read_csv('vaccinations.csv')
df_time = pd.read_csv('vaccinations.csv')
df_time["date"] = pd.to_datetime(df_time["date"], format = '%Y-%m-%d')
df_time = df_time.replace([np.inf, -np.inf], np.nan)
df_time = df_time.fillna(0)
df.head()
df.info()
Описание колонок
bf country - страна. в которой была проведена вакцинация
iso_code - код страны
date - дата ввода информации
total_vaccionations - число вакцины
people_vaccinated - число сделанных прививок в данной стране
people_fully_vaccinated - число людей, прошедших полную вакцинацую (она включает обычно 2 прививки)
daily_vaccinations_raw - число вакцинаций на день записи
total_vaccinations_per_hundred - количество примененных доз вакцины на 100 человек населения
people_vaccinated_per_hundred - количество людей с иммунитетом на 100 человек населения
people_fully_vaccinated_per_hundred -количество людей, прошедших полную вацинациб на 100 человек населения
daily_vaccinations_per_million - отношение в промилях числа вацинированных и общей численностью населения
vaccines - число вакцин, используемых в данной стране
source_name - источник информации
source_website - вебсайт источника
Постановка задачи: используя даннные, проанализировать, на каком этапе вакцинации находятся страны мира, узнать, какая из стран занимает лидирующую позицию по количеству сделанных вакцин, а также по процентному соотношению вакцинированных людей (два разных понятия). Кроме того, построить прогноз общего количества сделанных вакцин ближайшую неделю
Мы имеем дело с данными, датированными с конца декабря 2020 по май 2021 года
source_name и source_website в данной задаче нас не истересуют, их можно исключить
df = df.drop(['source_name', 'source_website'], axis=1)
Поскольку проект связан с анализом числа стран, в которых была проведена вакцинация, удалим нулевые строки total_vaccinations
df = df.drop(df[df.total_vaccinations.isna()].index)
iso_code страны тоже можно исключить
df = df.drop(['iso_code'], axis=1)
Дальнейшая предобработка данных по исключению нанов пройдет по мере необходимости в разделах "визуальный анализ данных" и "прогнозирование временного ряда"
Рассморим, что из себя представляет наш датасет. Построим для начала тепловую карту, которая дает нам информацию о связях между данными таблицы
people_vaccinated_not_none = df.drop(df[df.people_vaccinated.isna()].index)
plt.subplots(figsize=(10, 10))
sns.heatmap(people_vaccinated_not_none.corr(), annot=True)
plt.show()
Для наглядности построим интеграктивны график зависимости количества людей, прошедших полную вакцинацию для каждого из дней
people_fully_vaccinated_per_hundred_not_none = df.drop(df[df.people_fully_vaccinated_per_hundred.isna()].index)
fig = px.line(people_fully_vaccinated_per_hundred_not_none, x="date", y="people_fully_vaccinated_per_hundred", color='country')
fig.show()
Для наглядности выведем в качестве диаграммы топ 15 стран
countries_total_vaccinations = df.groupby(["country",'vaccines'])['total_vaccinations','people_vaccinated','people_fully_vaccinated',
'daily_vaccinations','total_vaccinations_per_hundred','people_vaccinated_per_hundred',
"people_fully_vaccinated_per_hundred",'daily_vaccinations_per_million'].max().reset_index()
data = countries_total_vaccinations[['country','people_fully_vaccinated_per_hundred']].nlargest(15,'people_fully_vaccinated_per_hundred')
fig = px.bar(data, x = 'country',y = 'people_fully_vaccinated_per_hundred',
title="топ 15 стран по количеству людей, прошедших полную вакцинацию показатель на 100 человек населения",
labels = {'country': 'страны', 'people_fully_vaccinated_per_hundred' :'показатель на 100 человек населения'})
px.xlabel = "страна"
fig.show()
Из графика видно, что лидирующие позиции по полной вакцинации населения занимают Гибралтар, Израиль и Сейшельские Острова
Стоит заметить, что информация, полученная из датасета, соответствует действительности и новостным лентам. Гибралтар первым в мире завершил вакцинацию всего взрослого населения. Также как и Израиль, который является мировым лидером по вакцинации населения
Посмотрим, какие из стран сделали наибольшее число прививок
top_total_vaccinations = df.groupby('country').people_vaccinated.max().sort_values(ascending=False)
total_vaccinations_f = top_total_vaccinations.dropna(axis=0).reset_index()
display(total_vaccinations_f[0:7])
plt.figure(figsize=(10, 5))
plt.title('Топ стран с наибольшим числом вакцинированного населения)')
sns.barplot(x=total_vaccinations_f.country[0:7], y=total_vaccinations_f['people_vaccinated'])
plt.ylabel('Число вакцинированных людей (млн)');
Хотя США занимает первое место по числу вакцинированного населения, однако доля вакцинированных людей равна 30%, однако в Индии этот показатель вообще равняется 2%. Значимую роль все-так играет предыдущий показатель
data = countries_total_vaccinations[['country','total_vaccinations']].nlargest(15,'total_vaccinations')
fig = px.bar(data, x = 'country',y = 'total_vaccinations',
title="Общее число сделанных вакцинаций топ 15 стран",
labels = {'country': 'страны', 'total_vaccinations' :'общее число вакцинаций'})
px.xlabel = "страна"
fig.show()
Посмотрим, на каком месте находится Россия:
data = countries_total_vaccinations[['country','people_fully_vaccinated']].nlargest(15,'people_fully_vaccinated')
fig = px.bar(data, x = 'country',y = 'people_fully_vaccinated',
title="топ 15 стран по количеству людей, прошедших полную вакцинацию",
labels = {'country': 'страны', 'people_fully_vaccinated' :'число вакцинированного населения'})
px.xlabel = "страна"
fig.show()
Можно заметить, что нет единой страны, которая бы занимала лидирующую позицию в каждом из проанализированных аспектов.
Таким образом, имеем следующие результаты:
Следующим вопросом изучения является: какая вакцина применяется наиболее часто?
df= df.drop(df[df.people_fully_vaccinated.isna()].index)
Рассмотрим, какие вакцины применяются в различных странах мира
df['vaccines'].unique().shape
Таким образом, мы имеем дело с 34 типами вакцин
Сделаем группироку по странам
vaccines = df.groupby(['vaccines'])['country'].unique()
vaccines = vaccines.reset_index()
vaccines
Для наглядности построим barplot диаграмму, которая показывает, какое количество стран применяет ту или иную вакцину, а для начала сгруппируем по странам
new_df = df.groupby(["country",'vaccines'])['total_vaccinations','people_vaccinated','people_fully_vaccinated',
'daily_vaccinations','total_vaccinations_per_hundred','people_vaccinated_per_hundred',
"people_fully_vaccinated_per_hundred",'daily_vaccinations_per_million'].max().reset_index()
list_of_vaccines = new_df.reset_index().groupby(['vaccines'])['country'].count().sort_values(ascending=False)
list_of_vaccines = list_of_vaccines.reset_index()
with sns.plotting_context('notebook', font_scale = 2):
plt.figure(figsize=(20, 20))
plt.title('Распространение вакцины')
sns.barplot(y=list_of_vaccines.vaccines, x=list_of_vaccines.country)
plt.ylabel(' ')
Топ 3 группы вакцин:
Предположим, что среднее значение прививок, сделанных в марте, будет выше среднего значения прививок, сделанных в апреле
$H_0$ среднее значение ежедневного количества прививок, сделанных в марте, равно среднему значению ежедневного количества прививок, сделанных в апреле
$H_1$ среднее значение ежедневного количества прививок, сделанных в марте, больше среднего значения ежедневного количества прививок, сделанных в апреле
df["date"] = pd.to_datetime(df["date"], format = '%Y-%m-%d')
df = df.replace([np.inf, -np.inf], np.nan)
df = df.fillna(0)
daily_data = df[['daily_vaccinations','date']].groupby('date',as_index = False).sum()
daily_data['vac_test'] = daily_data['daily_vaccinations']
daily_data['year'] = daily_data['date'].dt.year
daily_data['month'] = daily_data['date'].dt.month
daily_data['day'] = daily_data['date'].dt.day
df['month'] = df['date'].dt.month
jan_month = df[df['month'] == 1]['daily_vaccinations']
feb_month = df[df['month'] == 2]['daily_vaccinations']
march_month = df[df['month'] == 3]['daily_vaccinations']
april_month = df[df['month'] == 4]['daily_vaccinations']
may_month = df[df['month'] == 5]['daily_vaccinations']
scipy.stats.ttest_ind(march_month, april_month)
p value > 0.05, значит мы отклоняем нулевую гипотезу, что соответсвует тому, что среднее значение количества ежедневных прививок, сделанных в марте. равно среднему значению ежедневного количества прививок, сделанных в апреле
А теперь сделаем то же самое сравнение для апреля и февраля, и убедимся, что средние различны
$H_0$ среднее значение ежедневного количества прививок, сделанных в феврале, равно среднему значению ежедневного количества прививок, сделанных в апреле
$H_1$ среднее значение ежедневного количества прививок, сделанных в феврале, больше среднего значения ежедневного количества прививок, сделанных в апреле
scipy.stats.ttest_ind(feb_month, april_month)
Гипотеза $H_1$ подвтерждается
people_vaccinated_data = df.drop(df[df.people_vaccinated.isna()].index)
people_vaccinated_data = df.drop(df[df.total_vaccinations.isna()].index)
people_vaccinated_data.isna().sum()
Исходя из таблицы и из таблицы корреляции, можно предположить, что число сделанных за все время вакцинаций по каждой стране равно числу людей, прошедших вакцинацию
Проверим это с помощью U-критерия Манна — Уитни
Сформулируем гипотезы:
$H_0$ - число сделанных за все время вакцинаций в каждой стране равно числу людей, прошедших полную вакцинацию
$H_1$ - число сделанных за все время вакцинаций в каждой стране отличается от числа людей, прошедших полную вакцинацию
scipy.stats.mannwhitneyu(people_vaccinated_data.total_vaccinations, people_vaccinated_data.people_vaccinated, alternative='two-sided')
p value < 0.05, значит мы отвергаем нулевую гипотезу
$H_0$ - число сделанных за все время вакцинаций в каждой стране и число людей, прошедших полную вакцинацию, имеют одинаковое распределение
$H_1$ - число сделанных за все время вакцинаций в каждой стране и число людей, прошедших полную вакцинацию, взяты из различных распределений
scipy.stats.ranksums(df.total_vaccinations, df.people_vaccinated)
p value < 0.05, значит мы отвергаем нулевую гипотезу
df_pred = pd.read_csv('vaccinations.csv')
check_data = df_pred.drop(df_pred[df_pred.people_vaccinated.isna()].index)
Заполним средними значениями
diff = check_data.total_vaccinations.mean() - check_data.people_vaccinated.mean()
diff_per_hundred = check_data.total_vaccinations_per_hundred.mean() - check_data.people_vaccinated_per_hundred.mean()
df_pred.people_vaccinated = df_pred.people_vaccinated.fillna(df_pred.total_vaccinations - diff)
df_pred.people_vaccinated_per_hundred = df_pred.people_vaccinated_per_hundred.fillna(df_pred.total_vaccinations_per_hundred - diff_per_hundred)
df_pred.daily_vaccinations = df_pred.daily_vaccinations.fillna(0)
df_pred.daily_vaccinations_per_million = df_pred.daily_vaccinations_per_million.fillna(0)
df_pred.people_fully_vaccinated = df_pred.people_fully_vaccinated.fillna(0)
df_pred.people_fully_vaccinated_per_hundred = df_pred.people_fully_vaccinated_per_hundred.fillna(0)
df_pred.daily_vaccinations_raw = df_pred.daily_vaccinations_raw.fillna(0)
timeseries_cov = df_pred[(['date', 'total_vaccinations'])].groupby('date').sum()[4:-1]
timeseries_cov
Проверим стационарность временного ряда. Для этого воспользуемся тестом Дики- Фуллера
$H_0=\phi=0$ - процесс случайного блуждания
$H_1=\phi\neq0$ $−1<1+\phi<1$ - стационарный процесс
print('p-value : {}'.format(sm.tsa.stattools.adfuller(timeseries_cov)[1]))
pvalue > 0.05. Принимаем нулевую гипотезу. Ряд нестационарный
Сделаем преобразования ряда. Для начала применим преобразование Бокса-Кокса, после чего выберем порядок дифференцирования. Дифференцированием( переход к попарным разностям его соседних значений) можно стабилизировать среднее значение ряда
timeseries_cov['total_vaccinations_box'], l = scipy.stats.boxcox(timeseries_cov.total_vaccinations)
print('p-value : {}'.format(sm.tsa.stattools.adfuller(timeseries_cov.drop(columns=['total_vaccinations']))[1]))
timeseries_cov['total_vaccinations_box_diff1int2'] = timeseries_cov.total_vaccinations_box - timeseries_cov.total_vaccinations_box.shift(2)
timeseries_cov['total_vaccinations_box_diff2int2'] = timeseries_cov['total_vaccinations_box_diff1int2'] - timeseries_cov['total_vaccinations_box_diff1int2'].shift(2)
print('p-value : {}'.format(sm.tsa.stattools.adfuller(timeseries_cov.drop(columns=['total_vaccinations', 'total_vaccinations_box', 'total_vaccinations_box_diff1int2'])[4:])[1]))
# STL-декомпозиция ряда
from pylab import rcParams
rcParams['figure.figsize'] = 12, 7
sm.tsa.seasonal_decompose(timeseries_cov.total_vaccinations_box_diff2int2[4:], period=1).plot()
plt.show()
plt.figure(figsize=(20, 7))
ax = plt.subplot(211)
sm.graphics.tsa.plot_acf(timeseries_cov.drop(columns=['total_vaccinations', 'total_vaccinations_box', 'total_vaccinations_box_diff1int2'])[4:],
lags=(len(timeseries_cov)-4)/4, ax=ax)
ax = plt.subplot(212)
sm.graphics.tsa.plot_pacf(timeseries_cov.drop(columns=['total_vaccinations', 'total_vaccinations_box', 'total_vaccinations_box_diff1int2'])[4:],
lags=(len(timeseries_cov)-4)/4, ax=ax)
plt.show()
d = 0
D = 2
timeseries_cov.total_vaccinations_box
Сделаем прогноз на неделю вперед
parameters = product(np.arange(0, 3), np.arange(0, 3), np.arange(0, 3), np.arange(0, 3))
%%time
results = []
best_aic = float('inf')
for param in tqdm(parameters):
try:
model = sm.tsa.statespace.SARIMAX(timeseries_cov.total_vaccinations_box, order=(param[0], d, param[1]),
seasonal_order=(param[2], D, param[3], 2)).fit(disp=False)
except:
continue
aic = model.aic
if aic < best_aic:
best_model = model
best_aic = aic
best_param = param
results.append([param, model.aic])
print(best_model.summary())
def invboxcox(y, l):
if l == 0:
return np.exp(y)
else:
return np.exp(np.log(l*y+1)/l)
timeseries_cov['arima'] = invboxcox(best_model.fittedvalues, l)
plt.figure(figsize=(20,7))
timeseries_cov.total_vaccinations.plot()
timeseries_cov.arima.plot(color='r')
plt.xticks(rotation=45)
plt.show()
date = ['2021-05-'+str(x) for x in range(6, 13)]
timeseries = timeseries_cov['total_vaccinations']
pred_df = pd.DataFrame(index=date)
pred_df['total_vaccinations'] = invboxcox(best_model.predict(start=139, end=145).values, l)
timeseries = pd.concat([timeseries, pred_df])
timeseries.drop(columns=[0])[-7:]
timeseries_cov['arima'] = invboxcox(best_model.fittedvalues, l)
plt.figure(figsize=(20,7))
timeseries.total_vaccinations.plot(color='r')
timeseries_cov.total_vaccinations.plot()
plt.show()
В работы была проанализирована актуальная ситуация, связанная с вакцинацией в различных странах мирах против коронавирусной инфекции
Был проведен подготовительный анализ данных, содержащий анализ датасета, наличие в нем непригодных для поставленных целей данных, удаление колонок, содержащих нулевую статистику по сделанным прививкам
Проведен визуальный анализ данных, содержащий различные типы графиков, использована библиотека seaborn. Был сделан следующий вывод:
Были проверены статистические гипотезы с использованием параметрического и непараметрического критериев. Статистические критерии позволили отвергнуть гипотезу, гласившую, что число сделанных за все время вакцинаций по каждой стране равно числу людей, прошедших вакцинацию (предположение было сделано на основании таблицы, где эти значения совпадали, а также коэффициенте корреляции)
Было прооведено предсказание временного ряда общего числа вакцинаций в мире на последующие 7 дней. По прогнозу был получен рост числа вакцинаций